﻿using System;
using System.Diagnostics;
using System.IO;
using CommandLine;
using CommandLine.Text;
using Koonfusion.SyncDeploy.Core;
using System.Linq;



namespace SyncDeploy.Client
{
    class Client
    {
        private static Stopwatch _sw = new Stopwatch();
        private static string[] _args;

        private static string GetValue(string key, bool required)
        {
            try
            {

                foreach (var s in _args)
                {
                    var cleanArg = s.TrimStart('/', '-', ' ');

                    if (cleanArg.StartsWith(key, StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (cleanArg.IndexOf(':') != -1)
                        {
                            return cleanArg.Substring(cleanArg.IndexOf(':') + 1);
                        }

                        return String.Empty;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            if (required)
            {
                Console.WriteLine("Missing or invalid '{0}' parameter", key);
                Environment.Exit(-1);
            }

            return null;
        }


        private static void PrintHelp()
        {
            Console.WriteLine("Help!!!!!");
            Environment.Exit(-1);
        }


        private static void CreateDef()
        {
            var source = new DirectoryInfo(GetValue("source", true));
            var dest = new DirectoryInfo(GetValue("target", true));
            var name = GetValue("name", true);
            var version = GetValue("version", false);

            if (!source.Exists)
            {
                Console.WriteLine("Invalid source folder {0}", source);
                Environment.Exit(-1);
            }

            var defProvider = new ManifestBuilder();

            defProvider.OnFileProcessed += DefOnFileProcessed;
            defProvider.OnStart += DefOnStart;
            defProvider.OnSuccess += DefOnSuccess;

            defProvider.CreatePackage(source, dest, name, version);
        }


        private static void ExtractDef()
        {
            var source = new Uri(GetValue("source", true));
            var dest = new DirectoryInfo(GetValue("target", true));

            var defProvider = new ManifestExtractor();

            defProvider.OnFileProcessed += DefOnFileProcessed;
            defProvider.OnStart += DefOnStart;
            defProvider.OnSuccess += DefOnSuccess;

        }

        static void Main(string[] args)
        {

            foreach (var s in args)
            {
                Console.WriteLine(s);
            }

            AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
            _args = args;

            if (args == null || args.Length == 0)
            {
                PrintHelp();
            }
            else if (GetValue("create", false) != null)
            {
                CreateDef();
            }
            else if (GetValue("extract", false) != null)
            {
                ExtractDef();
            }
            else
            {
                Console.WriteLine("Must specify '/create' or '/extract'");
                PrintHelp();
            }

            Console.WriteLine("Press any key to continue...");
            Console.ReadLine();
        }

        static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Console.Error.WriteLine();
            Console.Error.WriteLine("======================================================================");
            Console.Error.WriteLine("An Unexpected error has occurred. {0}", e.ExceptionObject);
            Environment.Exit(-1);
        }

        static void DefOnSuccess(object sender, EventArgs e)
        {
            _sw.Stop();
            Console.WriteLine();
            Console.WriteLine("======================================================================");
            var def = (ManifestBuilder)sender;
            Console.WriteLine("Definition Generated Successfully");
            Console.WriteLine("{0:0,0} Files Processed in {1}.{2:00}s", def.SourceFileList.Length, _sw.Elapsed.Seconds, _sw.Elapsed.Milliseconds / 10);
            double rawSize = def.SourceFileList.Sum(c => c.Length);
            double zipSize = def.Destination.GetFiles("*.zip").Sum(c => c.Length);
            Console.WriteLine("Size Before Compression: {0:0.00} MB", rawSize / 1048576);
            Console.WriteLine("Size After Compression: {0:0.00} MB", zipSize / 1048576);
            Console.WriteLine("Compression Ratio {0:0}% (Lower is better) ", (zipSize / rawSize) * 100);
        }

        static void DefOnStart(object sender, EventArgs e)
        {
            _sw = Stopwatch.StartNew();
            var def = (ManifestBuilder)sender;
            Console.WriteLine("Generating Update Definition '{0}'. Total number of files {1}", def.Name, def.SourceFileList.Length);
        }

        static void DefOnFileProcessed(ManifestProcessorBase sender, FileInfo file)
        {
            Console.WriteLine("Processed: {0}", file.FullName);
        }

    }
}